package com.project.common.filter;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSONObject;
import com.project.common.utils.ServletUtils;
import com.project.common.utils.StringUtils;
import com.project.common.utils.uuid.IdUtils;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.util.SelectUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.MDC;
import org.springframework.core.Ordered;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import org.springframework.web.util.WebUtils;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;

/**
 * 日志打印添加 链路追踪
 */
@Component
@Slf4j
public class WebLogFilter extends OncePerRequestFilter implements Ordered {

    /**
     * 请在 logback.xml 文件中改写日志打印模板
     * <property name="log.pattern" value="[%d{yyyy-MM-dd HH:mm:ss.SSS} %5level][%thread] %logger{20}-%method,%-5.5line : [%X{traceId}] - %msg%n" />
     */
    public static final String TRACE_ID = "traceId";


    @Override
    public int getOrder() {
        /**
         * 将过滤器放在所有其他过滤器的末尾，以确保我们在处理所有其他过滤器之后
         */
        return Ordered.HIGHEST_PRECEDENCE + 10;
    }


    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //日志trade
        MDC.put(TRACE_ID, IdUtils.simpleUUID());

        log.info("接口请求信息 ==> {}", parseRequestData(request));

        filterChain.doFilter(request, response);

        ContentCachingResponseWrapper wrapperResponse = new ContentCachingResponseWrapper(response);
        log.info("接口 ==> 响应状态码：{} 响应数据：{} ", wrapperResponse.getStatusCode(), StringUtils.limit(parseResponseData(request, wrapperResponse), 2000));

        wrapperResponse.copyBodyToResponse();
        MDC.remove(TRACE_ID);
    }

    /**
     * 解析响应数据
     */
    private String parseResponseData(HttpServletRequest request, ContentCachingResponseWrapper response) {
        String uri = request.getRequestURI();
        if (uri.contains(".js")
                || uri.contains(".html")
                || uri.contains(".jquery")
                || uri.contains(".css")) {
            return "";
        }

        ContentCachingResponseWrapper wrapper = WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
        if (wrapper != null) {
            byte[] buf = wrapper.getContentAsByteArray();
            if (buf.length > 0) {
                try {
                    return new String(buf, 0, buf.length, wrapper.getCharacterEncoding());
                } catch (UnsupportedEncodingException e) {
                    log.error(" 解析响应数据失败！");
                }
            }
        }
        return "";
    }

    /**
     * 解析请求数据
     */
    private String parseRequestData(HttpServletRequest request) {

        String url = request.getRequestURI();
        Object formParams = CollUtil.isEmpty(request.getParameterMap()) ? "" : request.getParameterMap();
        Object bodyParams = "";

        try {
            bodyParams = JSONObject.parseObject(IOUtils.toString(request.getInputStream()));
        } catch (IOException e) {
            log.error("解析数据失败");
        }

        return new JSONObject(new LinkedHashMap<>())
                .fluentPut("url", url)
                .fluentPut("form参数", formParams)
                .fluentPut("body参数", bodyParams)
                .toJSONString();
    }
}
